#ifndef PERMUTATION_H
#define PERMUTATION_H
#include <vector>
#include <string>
#include "Helpers.h"

using std::vector;
using std::string;

class Permutation; 

class RelatedPermutation
{
public:
	RelatedPermutation(int groupIndex, int intersection, int groupSize): m_GroupIndex(groupIndex), m_Intersection(intersection), m_GroupSize(groupSize){};
	int GetIndex() const { return m_GroupIndex; };
	int GetIntersection() const { return m_Intersection; };
	int GetGroupSize() const { return m_GroupSize; };
	bool operator== (const RelatedPermutation &other) const;
	bool operator!= (const RelatedPermutation &other) const;

private:
	int m_Intersection;
	int m_GroupIndex;
	int m_GroupSize;
};

class Permutation
{
public:
	Permutation(VERTEX_SIZE *permutationList,int wordLen, int groupSize);
	Permutation(VERTEX_SIZE *permutationList,int wordLen, int groupSize, int name);
	~Permutation(void);
	int Permutation::CountIntersection(VERTEX_SIZE* groupB, int groupBrows);
	vector<bool> *GetMatrixColumns() const;
	VERTEX_SIZE *GetMatrixRows() const;
	void UpdateMatrix(VERTEX_SIZE* newPerm, int newGroupSize);
	int GetGroupSize() const; 
	static VERTEX_SIZE* GetMatrixWithoutIntersection(VERTEX_SIZE* matrixToClean, int matrixToCleanRows, VERTEX_SIZE* otherMatrix, int otherMatrixRows, int intersectionSize);
	Permutation *NextPermutation();
	bool operator== (const Permutation &other) const;
	bool operator!= (const Permutation &other) const;
	void AddRelatedPerm(RelatedPermutation other);
	vector<RelatedPermutation>::iterator GetRelatedPermsBegin() { return m_RelatedPerms.begin();};
	vector<RelatedPermutation>::iterator GetRelatedPermsEnd() { return m_RelatedPerms.end();};
	int GetRelatedPermsCount() {return m_RelatedPerms.size();};
	Permutation *Clone() const;
	void SetName(const int name) { m_GroupIndex=name; };
	int GetName() const { return m_GroupIndex; };
	int GetWordLen() const { return m_WordLen; };
	vector<bool> **GetAllVertexNames();

	static VERTEX_SIZE* TransposeColumnMatrixBit(vector<bool>* matrix, int rows, int cols);

private:
	int m_WordLen; // How long is each binary word - column count
	int m_GroupSize; // How many words are in group
	VERTEX_SIZE *m_Permutation; // List of binary words (the matrix rows)
	vector<RelatedPermutation> m_RelatedPerms;
	int m_GroupIndex;

	vector<bool>* TransposeMatrixBits(const int rowCount, const int colCount) const;
		vector<bool> *Permutation::GetVertexNameBool(VERTEX_SIZE vertex) const;
	static int CleanPermutation(VERTEX_SIZE **permPointer, int size); 
	void Swap(std::vector<VERTEX_SIZE>& sourceVector, int index1, int index2);

	static const int NO_INDEX = -1;
};

#endif
